package com.example.callbackservice.serviceImpl;

import com.example.api.service.CallbackService;
import com.example.api.service.OpenApiAppService;
import com.example.callbackservice.entity.CallbackComponent;
import com.example.callbackservice.entity.vo.CallbackEventBaseVO;
import com.example.callbackservice.entity.vo.CodeQualityResult;
import com.example.callbackservice.entity.vo.Header;
import com.example.callbackservice.entity.vo.Message;
import com.example.common.constant.ApiParamConsts;
import com.example.common.core.AjaxResult;
import com.example.common.entity.CallbackConfig;
import com.example.common.entity.CodeQualityRes;
import com.example.common.entity.ConfigCallbackDTO;
import com.example.common.entity.OpenApiApp;
import com.example.common.exception.BaseException;
import com.example.common.exception.ExceptionCode;
import com.example.common.utils.CryptUtil;
import com.example.common.utils.SHA1;
import com.example.common.utils.StringUtils;
import com.example.common.utils.WillingAESUtils;
import com.example.callbackservice.util.CallbackUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.net.URLEncoder;
import java.util.Objects;

/**
 * @author DestinyCc
 * @date 2022/4/16
 */
@Slf4j
@Service(protocol = "dubbo")
public class CallbackServiceImpl implements CallbackService {

    @Autowired
    RestTemplate restTemplate;

    @Reference
    OpenApiAppService openApiAppService;

    @SneakyThrows
    @Override
    public AjaxResult configCallback(ConfigCallbackDTO configCallbackDTO) {
        String token = configCallbackDTO.getToken();
        String encodingAesKey = configCallbackDTO.getEncodingAesKey();
        String appId = configCallbackDTO.getAppId();
        String callbackUrl = configCallbackDTO.getCallbackUrl();
        OpenApiApp apiApp = openApiAppService.getAppByAppIdAndSecret(appId, WillingAESUtils.encrypt(configCallbackDTO.getAppSecret()));
        if (Objects.isNull(apiApp)) {
            throw new BaseException(ExceptionCode.PARAM_NOT_VALID, "appId或appSecret不合法");
        }
        CryptUtil cryptUtil = new CryptUtil(token, encodingAesKey, appId);
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        // 随机生成8位的字符串
        String helloMsg = CryptUtil.genRandomStr(8);
        String encryptedMsg = cryptUtil.encrypt(CryptUtil.genRandomStr(16), helloMsg);
        log.info("echoStr = {}", encryptedMsg);
        String nonce = CryptUtil.genRandomStr(16);
        log.info("nonce = {}", nonce);
        String msgSignature = SHA1.gen(token, timeStamp, nonce, encryptedMsg);
        log.info("signature = {}", msgSignature);
        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(callbackUrl)
                .queryParam(ApiParamConsts.CallBack.MSG_SIGNATURE, URLEncoder.encode(msgSignature, "UTF-8"))
                .queryParam(ApiParamConsts.CallBack.TIMESTAMP, URLEncoder.encode(timeStamp, "UTF-8"))
                .queryParam(ApiParamConsts.CallBack.NONCE, URLEncoder.encode(nonce, "UTF-8"))
                .queryParam(ApiParamConsts.CallBack.ECHOSTR, URLEncoder.encode(encryptedMsg, "UTF-8"));
        URI uri = builder.build(true).toUri();
        String receivedMsg = restTemplate.getForObject(uri, String.class);
        log.info("raw = {}", helloMsg);
        log.info("received = {}", receivedMsg);
        if (StringUtils.isEmpty(receivedMsg) || !Objects.equals(receivedMsg, helloMsg)) {
            throw new BaseException(ExceptionCode.PARAM_NOT_VALID);
        }
        apiApp.setToken(WillingAESUtils.encrypt(token));
        apiApp.setEncodingAesKey(WillingAESUtils.encrypt(encodingAesKey));
        apiApp.setCallbackUrl(callbackUrl);
        openApiAppService.updateByPrimaryKeySelective(apiApp);
        return AjaxResult.success("配置成功");
    }

    @Override
    @SneakyThrows
    public <T> void doCallback(T data, String tenantId, String appId, String eventType) {
//        String className = data.getClass().getCanonicalName();
//        switch (className){
//            case "com.example.common.entity.CodeQualityRes":
////                result = (CodeQualityRes) data;
////                result = new CodeQualityResult(res.getReliability(), res.getCodeQualities());
//                break;
//            default:
//        }
        CallbackConfig cfg = openApiAppService.getCallbackCfgByIdAndAppId(tenantId, appId);
        if (Objects.nonNull(cfg) && StringUtils.isNotEmpty(cfg.getCallbackUrl())){
            //加密前的header部分
            Header header = new Header(eventType, String.valueOf(System.currentTimeMillis() / 1000), cfg.getAppId());
            //加密前的msg，包含header和event
            Message msg = new Message(header, data);
            //构建callback所需的所有参数
            CallbackComponent component = CallbackUtils.buildCallbackComponent(cfg, msg);
            String url = cfg.getCallbackUrl();
            UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).
                    queryParam(ApiParamConsts.CallBack.MSG_SIGNATURE, component.getMsgSignature()).
                    queryParam(ApiParamConsts.CallBack.TIMESTAMP, component.getTimeStamp()).
                    queryParam(ApiParamConsts.CallBack.NONCE, component.getNonce());
            URI uri = builder.build(true).toUri();
            HttpEntity request = CallbackUtils.buildBody(cfg.getAppId(), component.getEncrypted());
            String response = restTemplate.postForObject(uri, request, String.class);
//            if ("success".equals(response)) {
//                return;
//            }
        }
    }


}
